package com.minelx.datamicroscope.common;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import io.gitee.minelx.filesystem.File;
import io.gitee.minelx.filesystem.Path;
import io.gitee.minelx.filesystem.provider.FS;
import io.gitee.minelx.commontools.Files;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

import static io.gitee.minelx.filesystem.init.OpenPolicy.EXISTS;

public class Configurations {
	
	private static final Map<String, JSON> cache = new HashMap<>();

	private final String configPath;

	private Configurations(String configPath) {
		this.configPath = configPath;
	}

	@SuppressWarnings("unchecked")
	public <R extends JSON> R toJSON() {
		// returns cached configuration if contains
		if (cache.containsKey(configPath)) {
			return (R) cache.get(configPath);
		}
		// create new configuration and bind it to cache
		R newConfiguration = createNewConfiguration();
		cache.put(configPath, newConfiguration);
		return newConfiguration;
	}

	private <R extends JSON> R createNewConfiguration() {
		// check if local storage configuration is existed
		Path localStorageConfiguration = FS.workingDir().child().path(configPath);
		if (localStorageConfiguration.exists()) {
			try {
				return parseToJSON(File.create(localStorageConfiguration, EXISTS).read(StandardCharsets.UTF_8));
			} catch (IOException e) {
				throw new RuntimeException("error while reading configuration at: " + localStorageConfiguration.absolutePath(), e);
			}
		}
		// there is no local storage configuration, we choose default configuration inside jar achieve
		return parseToJSON(Files.toString(configPath, StandardCharsets.UTF_8));
	}

	private <R extends JSON> R parseToJSON(String text) {
		//noinspection unchecked
		return (R) JSON.parse(text);
	}

	public JSONObject toJSONObject() {
		return toJSON();
	}

	public JSONArray toJSONArray() {
		return toJSON();
	}

	public static Configurations of(String configPath) {
		return new Configurations(preprocessConfigPath(configPath));
	}

	private static String preprocessConfigPath(String configPath) {
		return addPrefixIfNeeded(addSuffixIfNeeded(configPath));
	}

	private static String addPrefixIfNeeded(String configPath) {
		if (configPath.startsWith("/")) {
			return configPath;
		}
		return "/" + configPath;
	}

	private static String addSuffixIfNeeded(String configPath) {
		if (configPath.endsWith(".json")) {
			return configPath;
		}
		return configPath + ".json";
	}
}
